import { computed, ComputedRef, onMounted, shallowRef } from 'vue'
import { getCache, removeCache, setCache } from '../cache'
import { serverTime } from '../server';


interface CountdownOutType {
  isDisabled: ComputedRef<boolean>
  onSend: () => Promise<any>
  text: ComputedRef<string>
}

export function useCountdown(cb: () => Promise<any>): CountdownOutType {
  const countdown = shallowRef(0)
  const isSending = shallowRef(false)
  const text = computed((): string => (countdown.value ? countdown.value + '秒后重发' : '发送验证码'))
  const isDisabled = computed(() => isSending.value || Boolean(countdown.value))

  const updateCountdown = (val: number): void => {
    countdown.value = val
  }

  onMounted(() => countdownStorage(60, updateCountdown))

  const onSend = async (): Promise<any> => {
    try {
      isSending.value = true
      await cb()
      countdownStorage(60, updateCountdown, true)
    } finally {
      isSending.value = false
    }
  }

  return {
    isDisabled,
    onSend,
    text,
  }
}

function countdown(options: any = {}): void {
  const cb = options.cb
  const beginTime = options.beginTime || serverTime.value
  const endTime = options.endTime
  const delay = options.delay || 1000
  const diff = serverTime.value - beginTime
  let restTime = endTime - (beginTime + diff)
  let isEnd = false
  let currentTime = null
  let timer: any = -1

  function handler(): void {
    restTime = endTime - serverTime.value - diff
    if (restTime < delay) {
      restTime = 0
      isEnd = true
      clearInterval(timer)
    }
    currentTime = endTime - restTime
    cb({
      restTime,
      currentTime,
      endTime,
      isEnd,
    })
  }

  handler()
  timer = setInterval(handler, delay)
}

export function countdownStorage(second: number, cb: (num: number) => void, restart?: boolean, id?: any): void {
  if (!id) {
    id = 'SMS_CODE'
  }
  const cache = getCache(id, {
    currentTime: 0,
    endTime: serverTime.value + 1000 * second,
    number: 0,
  })
  if (cache.number > 0 || restart) {
    countdown({
      beginTime: cache.currentTime,
      cb: ({ restTime, currentTime, endTime, isEnd }: any): void => {
        cache.currentTime = currentTime
        cache.endTime = endTime
        cache.number = Math.round(restTime / 1000)
        cb(cache.number)
        setCache(id, cache, endTime)
        if (isEnd) {
          removeCache(id)
        }
      },
      endTime: cache.endTime,
    })
  }
}
